﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace PSL.Stack
{
    /// <summary>
    /// Function in the psl-runtime, intern and extern
    /// </summary>
    internal class Function
    {
        #region Private Member
        private FunctionType functionType;
        private string functionName;

        // Extern function, member
        private Delegate externMethodDelegate;

        // Intern function, member
        private ST.DeclareFunctionNode functionDeclaration;

        // Engine
        private PSLRuntime engine;
        #endregion

        #region Constructor
        /// <summary>
        /// Crate function which call a psl-function
        /// </summary>
        /// <param name="FunctionDeclaration">Return-value of the psl-function</param>
        internal Function(PSLRuntime Engine, ST.DeclareFunctionNode FunctionDeclaration)
            : this(Engine)
        {
            functionName = FunctionDeclaration.FunctionName;
            functionType = PSL.FunctionType.PSLFunction;
        }

        /// <summary>
        /// Create function which call an .net method
        /// </summary>
        /// <param name="FunctionName">Name of the function</param>
        /// <param name="Event">Delegate to the .net method</param>
        internal Function(PSLRuntime Engine, string FunctionName, Delegate Delegate)
            : this(Engine)
        {
            functionName = FunctionName;
            externMethodDelegate = Delegate;
            functionType = PSL.FunctionType.ExternFunction;
        }

        /// <summary>
        /// Private Base-Constructor
        /// </summary>
        /// <param name="Engine">Instance of an psl-engien</param>
        private Function(PSLRuntime Engine)
        {
            engine = Engine;
        }
        #endregion

        #region Public Methods
        /// <summary>
        /// Call the current function
        /// </summary>
        /// <param name="Parameter">Parameter of the function</param>
        /// <returns>Return-value of the function</returns>
        public dynamic Call(object[] Parameter)
        {
            if (functionType == PSL.FunctionType.ExternFunction)
            {
                // call the extern function and return the result to the runtime
                return externMethodDelegate.DynamicInvoke(Parameter);
            }
            else
            {
                // Call the intern-function over the runtime
                return engine.Runtime.CallInternFunction(functionDeclaration);
            }
        }
        #endregion

        #region Public Member
        /// <summary>
        /// Type of the function, for example intern, extern
        /// </summary>
        internal FunctionType FunctionType
        {
            get { return functionType; }
        }
        #endregion
    }
}
